PowerTCP Mail for .NET
Designed for Modern Applications



PowerTCP Mail for .NET exposes a modern multi-threaded design with technical advantages over competing products.


Async Methods

The async methods (BeginXXX) seen in competing products reflect an antiquated single-threaded design model that denies the benefits of multiple .NET worker threads. Please read on to see how PowerTCP Mail for .NET delivers native multi-threaded power to your application without adding the complexity that is often associated with multi-threading techniques.

Operation on the client side of the Internet mail client/server model is inherently command driven, so Mail for .NET provides a simple Start(delegate) method that executes the delegate function on a worker thread. This straight-forward concept provides a flexible technique for using PowerTCP in any application environment.

This design eliminates the need for BeginXXX methods and EndXXX events. There is a clean interface with one method for each function and several advantages are immediately realized:

Efficiency. Methods are designed to efficiently block on socket receive operations (the thread sleeps until bytes are received). This results in the most robust and efficient design possible.

Reusable code. Your delegate(s) can be used in applications both with and without a UI. It is no longer necessary to use BeginFoo for Windows Forms applications, and (the blocking) Foo for services, web applications and console applications.

Lower life-cycle cost. Code is written sequentially because there is no UI message pump to consider. It is not necessary to write code for numerous event handlers. Your code is self-documenting, easier to debug and maintain, and has a lower life-cycle cost.

Easy-to-implement parallel operation. Worker threads are easily spawned, supporting intensively parallel operations. Alternatively, serial operation is easily implemented by using a single thread. Flexibility of design is key.

No more state machine. It is not necessary to track state in event handlers. Take the simple case where the following sequence takes place:

Using BeginXXX, an event is raised when data is received and a state machine is required (if R1 is received then send S1, else if R2 is received then send S2). Using a single worker thread, the operation is coded in simple, declarative steps (Receive R1, Send S1, Receive R2, Send S2).


No More Pseudo-Blocking

Competing products use "pseudo-blocking" to process UI events while the method blocks. Without pseudo-blocking overhead methods are faster and more efficient. Also, re-entrancy problems (caused when UI messages are processes while a communication method is in progress) are no longer possible.


Developing Applications Without a UI

Developing console applications, web applications, services and other applications without a UI is as easy as ever. Sequential code performs efficiently. If parallel operation is desired, Start(delegate) can be used to execute code in any delegate body in parallel.


Developing Applications With a UI

Developing Windows Forms applications is now just as easy as writing applications without a UI. One method (the delegate) can be used in both types of applications. The only difference is that a UI app uses Start(delegate) to spawn a worker thread upon which the method executes, and any data needed by the UI must be marshaled to the UI thread. To this end, PowerTCP components include Start() and Marshal() convenience methods.


The Start Method

Use the Start method to execute one or more methods on a new worker thread, so the UI is not blocked during operation. The syntax for this method is simple:

C#
Copy Code
smtp1.Start(myBlockingFunction, myObject);

private void myBlockingFunction(object myObject)
{
   ...
}

Visual Basic
Copy Code
smtp1.Start(AddressOf myBlockingFunction, myObject)

Private Sub myBlockingFunction(ByVal myObject As Object)
   ...
End Sub

The state parameter for Start (myObject in this snippet) may be any object, including object arrays, allowing any number of discrete objects to be passed into the worker thread, which can then be cast back to their original types on the worker thread.

Marshaling Data

It is often necessary to pass information from a worker thread to update an element on the UI thread. Use the Marshal method for this purpose. Each Marshal overload is paired with an event that is raised on the UI thread. For example:

C#
Copy Code
smtp1.Marshal("Message from the worker thread!", null); //Execute on worker thread

private void smtp1_UserState(object sender, UserStateEventArgs e)
{
   //A message and/or an object was marshaled to the UI from a worker thread
   MessageBox.Show(e.Message);
}

Visual Basic
Copy Code
smtp1.Marshal("Message from the worker thread!", Nothing) 'Execute on worker thread

Private Sub smtp1_UserState(ByVal sender As Object, ByVal e As UserStateEventArgs) Handles smtp1.UserState
   'A message and/or an object was marshaled to the UI from a worker thread
   MessageBox.Show(e.Message)
End Sub

Just like Start, the state parameter for Marshal may be used to pass any object, including object arrays, over to the UI thread, which may then be cast back to their original type on the UI thread.

Typical Use

The developer wants to execute a series of functions without interfering with the user-interface. A button, textbox, and the PowerTCP Smtp component are added to the form. Pressing the button will initiate a session which creates and sends a mail message. A log of the session is displayed in the textbox. The sendMail function, which can be reused in a non-UI application, is passed to Start and executes on a worker thread.

C#
Copy Code
private void button1_Click(object sender, EventArgs e)
{
    //Send a message to the specified recipient
    //The Start method is used to execute the operation on a worker thread
    //(Event handlers were added in the designer)
    smtp1.Start(sendMail, "myRecipient@dart.com");
}

private void sendMail(object state)
{
    //This function executes on a worker thread without blocking the UI
    //Create message to send
    MailMessage message = new MailMessage();
    message.To = state as string;
    message.From = "sender@dart.com";
    message.Subject = "Here is your file";
    message.Text = "Please see the attached file.";
    message.Attachments.Add(new Attachment("myAttachment.doc"));

    //Set session parameters
    smtp1.Session.RemoteEndPoint =
        new Dart.Mail.IPEndPoint("myMailServer", Smtp.GetDefaultPort(smtp1.Session));
    smtp1.Session.Username = "myUsername";
    smtp1.Session.Password = "myPassword";

    //Send message and logout
    smtp1.Send(message);
    smtp1.Close();
}

private void smtp1_Connection_Log(object sender, DataEventArgs e)
{
    //Log the communication to a textbox
    textBox1.AppendText(e.Data.ToString());
}

private void smtp1_Error(object sender, ErrorEventArgs e)
{
    //Any unhandled exception on the worker thread will be automatically marshaled here.
    MessageBox.Show(e.GetException().Message, "Error during send");
}
Visual Basic
Copy Code
Private Sub button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles button1.Click
    'Send a message to the specified recipient
    'The Start method is used to execute the operation on a worker thread
    '(Event handlers were added in the designer)
    smtp1.Start(AddressOf sendMail, "myRecipient@dart.com")
End Sub

Private Sub sendMail(ByVal state As Object)
    'This function executes on a worker thread without blocking the UI
    'Create message to send
    Dim message As New MailMessage()
    message.To = TryCast(state, String)
    message.From = "sender@dart.com"
    message.Subject = "Here is your file"
    message.Text = "Please see the attached file."
    message.Attachments.Add(New Attachment("myAttachment.doc"))

    'Set session parameters
    smtp1.Session.RemoteEndPoint = New Dart.Mail.IPEndPoint("myMailServer", Smtp.GetDefaultPort(smtp1.Session))
    smtp1.Session.Username = "myUsername"
    smtp1.Session.Password = "myPassword"

    'Send message and logout
    smtp1.Send(message)
    smtp1.Close()
End Sub

Private Sub smtp1_Connection_Log(ByVal sender As Object, ByVal e As DataEventArgs)
    'Log the communication to a textbox
    textBox1.AppendText(e.Data.ToString())
End Sub

Private Sub smtp1_Error(ByVal sender As Object, ByVal e As ErrorEventArgs)
    'Any unhandled exception on the worker thread will be automatically marshaled here.
    MessageBox.Show(e.GetException().Message, "Error during send")
End Sub


PowerTCP Mail for .NET Documentation Version 4.3
© 2018 Dart Communications. All Rights Reserved.
Send comments on this topic